import { NextSeo } from 'next-seo';
import { Tab, Tabs } from 'nextra/components';

<NextSeo description="Learn how to run serverless console commands on AWS Lambda with Symfony Console or Laravel Artisan." />

# Console runtime

Bref's "Console" runtime lets us run CLI scripts on AWS Lambda.

This can be used to run PHP scripts, like cron tasks, the [Symfony Console](https://symfony.com/doc/current/console.html), [Laravel Artisan](https://laravel.com/docs/artisan), and more.

## How it works

When the function is invoked, the Console runtime will execute the PHP script defined as the *handler* in a sub-process.

The result of the execution (exit code and output) will be returned as the result of the AWS Lambda invocation. All the CLI output is also logged ([learn more about logs](../environment/logs.mdx)).

Console functions can be invoked:

- via a cron schedule
- via the `serverless bref:cli` command
- via the `bref command` command when using [Bref Cloud](/cloud)
- manually by invoking the function via the AWS API

## Usage

The Lambda function used for running console applications must use the `php-xx-console` runtime. Here is an example:

```yml filename="serverless.yml" {8-9}
service: app
provider:
    name: aws
plugins:
    - ./vendor/bref/bref
functions:
    hello:
        handler: the-php-script-to-run.php
        runtime: php-81-console
```

Behind the scenes, the `php-xx-console` runtime will deploy a Lambda function configured to use Bref's `php-81` AWS Lambda layer plus Bref's `console` layer (read more about these in the [runtimes documentation](../runtimes.mdx)).

## Running commands

When invoked, the "Console" runtime executes the `handler` script in a sub-process. For example, if the following handler was defined:

```yml filename="serverless.yml"
functions:
    hello:
        handler: the-php-script-to-run.php
        runtime: php-81-console
```

Then the following command would run in Lambda every time the function is invoked:

```sh
php the-php-script-to-run.php
```

The Lambda function can be invoked with a payload. It must be a JSON string, for example `"arg1 arg2 --option1=foo"`. Note that it is a string encoded in JSON, that is why it is in quotes, `json_decode($payload)` would return the string itself.

In our example, the following command would run in Lambda when invoked with such a payload:

```sh
php the-php-script-to-run.php arg1 arg2 --option1=foo
```

### Cron

Read the dedicated documentation for [running cron tasks on AWS Lambda](../use-cases/cron.mdx).

### CLI invocation

To manually run a console command on AWS Lambda, run the following command on your computer:

<Tabs items={['Serverless CLI', 'Bref Cloud']}>
    <Tab>
        ```bash
        serverless bref:cli --args="{arguments and options for the script}"
        ```

        The `bref:cli` command will automatically detect which function (in `serverless.yml`) uses the `console` runtime and will run the command on that function.

        Pass your command arguments and options in the `--args` flag (shortcut: `-a`). Remember to escape quotes properly. Some examples:

        ```bash
        # Runs the CLI application without arguments and displays the help
        $ serverless bref:cli
        # ...

        $ serverless bref:cli --args="doctrine:migrations:migrate"
        Your database will be migrated.
        To execute the SQL queries run the command with the `--force` option.

        $ serverless bref:cli -a "doctrine:migrations:migrate --force"
        Your database has been migrated.

        $ serverless bref:cli --stage=prod -a "db:dump --file='/tmp/dump.sql' --verbose"
        # ...

        # You can use environment variables to configure AWS credentials (e.g. in CI)
        $ AWS_ACCESS_KEY_ID=foo AWS_SECRET_ACCESS_KEY=bar serverless bref:cli
        # ...
        ```

        The `bref:cli` command can be used to run CLI commands in Lambda from your machine, but can also be used in CI/CD to run DB migrations for example.
    </Tab>
    <Tab>
        ```bash
        bref command "{arguments and options for the script}"
        ```

        It will automatically detect which function (in `serverless.yml`) uses the `console` runtime and will run the command on that function.

        Pass your command arguments and options as a single string. Remember to escape quotes properly. Some examples:

        ```bash
        # Runs the CLI application without arguments and displays the help
        $ bref command
        # ...

        $ bref command "doctrine:migrations:migrate"
        Your database will be migrated.
        To execute the SQL queries run the command with the `--force` option.

        $ bref command "doctrine:migrations:migrate --force"
        Your database has been migrated.

        $ bref command --env=prod "db:dump --file='/tmp/dump.sql' --verbose"
        # ...
        ```

        The `bref command` command can be used to run CLI commands in Lambda from your machine, but can also be used in CI/CD to run DB migrations for example.
    </Tab>
</Tabs>

### Interactive terminal

As an alternative to the CLI, the [Bref Dashboard](https://dashboard.bref.sh/?ref=bref) provides a convenient way to run commands via a terminal:

[![Bref Dashboard terminal for Laravel](../runtimes/dashboard-terminal.png)](https://dashboard.bref.sh/?ref=bref)

Functions using the "console" runtime are automatically detected, and colors are enabled by default for Laravel Artisan and Symfony Console.

### Without Serverless Framework

If you do not use `serverless.yml` but something else, like SAM/AWS CDK/Terraform, you can invoke your console function via the AWS CLI. For example:

```bash
aws lambda invoke \
    --function-name <console function name> \
    --region <region> \
    --cli-binary-format raw-in-base64-out \
    --payload '"<command arguments and options>"' \
    <file to store the output>.json

# For example:
aws lambda invoke \
    --function-name myapp-dev-myfunction \
    --region us-east-1 \
    --cli-binary-format raw-in-base64-out \
    --payload '"doctrine:migrations:migrate --force"' \
    response.json

# To extract the command output from the response.json file using jq
# https://stedolan.github.io/jq/
aws lambda invoke \
    --function-name myapp-dev-myfunction \
    --region us-east-1 \
    --cli-binary-format raw-in-base64-out \
    --payload '"doctrine:migrations:migrate --force"' \
    response.json && jq -r .output response.json
```

> **Note:**
> The `--payload` needs to contain a JSON string, that is why it is quoted twice: `'"..."'`. This is intentional.

## Lambda context

Lambda provides information about the invocation, function, and execution environment via the *lambda context*.

This context is usually available as a parameter (alongside the event), within the defined handler.
However, within the console runtime we do not have direct access to this parameter.
To work around that, Bref puts the Lambda context in the `$_SERVER['LAMBDA_INVOCATION_CONTEXT']` variable as a JSON-encoded string.

```php
$lambdaContext = json_decode($_SERVER['LAMBDA_INVOCATION_CONTEXT'], true);
```
